package com.cino.aspect;

import com.cino.annotation.AuditLog;
import com.cino.factory.AuditLogStorageStrategyFactory;
import com.cino.service.AsyncAuditLogService;
import com.cino.strategy.AuditLogStorageStrategy;
import com.cino.util.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 审计日志AOP切面
 * 
 * 功能说明：
 * 1. 拦截所有被@AuditLog注解标记的方法
 * 2. 支持CREATE、UPDATE、DELETE三种操作类型
 * 3. 支持自定义日志保存方法（targetMethod）
 * 4. 支持字段变更对比（UPDATE操作）
 * 5. 支持多种存储策略（MySQL、本地文件等）
 * 6. 异步保存审计日志，不影响业务性能
 * 
 * 执行流程：
 * 1. 设置拦截标记 → 2. 获取注解信息 → 3. 处理UPDATE操作（获取旧对象）
 * 4. 执行业务方法 → 5. 处理CREATE/UPDATE日志保存 → 6. 清理ThreadLocal
 */
@Slf4j
@Aspect
@Component
public class AuditLogAspect implements ApplicationContextAware {
    
    // ==================== 依赖注入 ====================
    
    /** 异步审计日志保存服务 */
    @Autowired
    private AsyncAuditLogService asyncAuditLogService;
    
    /** 审计日志存储策略工厂 */
    @Autowired
    private AuditLogStorageStrategyFactory strategyFactory;
    
    /** Spring应用上下文，用于获取自定义日志保存方法的Bean */
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    // ==================== AOP切点定义 ====================
    
    /**
     * 定义切点：所有被@AuditLog注解标记的方法
     * 这个切点会拦截所有带有@AuditLog注解的方法
     */
    @Pointcut("@annotation(com.cino.annotation.AuditLog)")
    public void auditLogPointcut() {
    }
    
    // ==================== 核心业务逻辑 ====================
    
    /**
     * 环绕通知：方法执行前后记录审计日志
     * 
 * 主要功能：
 * 1. 执行业务方法
 * 2. 收集审计信息（objectId、变更内容等）
 * 3. 根据注解配置选择存储策略（MySQL、本地文件等）
 * 4. 支持自定义日志保存方法（targetMethod）
 * 5. 异步保存审计日志
     * 
     * @param joinPoint 连接点，包含方法信息、参数等
     * @return 原方法的返回值
     * @throws Throwable 原方法可能抛出的异常
     */
    @Around("auditLogPointcut()")
    public Object auditLogAround(ProceedingJoinPoint joinPoint) throws Throwable {
        
        // 记录方法开始时间
        long startTime = System.currentTimeMillis();
        
        // 初始化审计状态和错误信息
        Integer auditStatus = 1; // 默认成功
        String errorMessage = null;
        String title = null;
        
        try {
            // ==================== 第一步：初始化设置 ====================
            
            // 设置拦截标记，告诉MyBatis拦截器需要捕获ID
            ThreadLocalUtil.setCaptureId(true);
            
            // 获取方法签名和注解信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            AuditLog auditLogAnnotation = method.getAnnotation(AuditLog.class);
            
            // 获取title值
            title = auditLogAnnotation.title();

            // 检查是否有自定义日志保存方法
            String customLogSaveMethod = auditLogAnnotation.targetMethod();
            boolean useCustomLogSave = customLogSaveMethod != null && !customLogSaveMethod.trim().isEmpty();
            
            // 获取自定义存储表名
            String storageTable = auditLogAnnotation.storageTable();
            
            // ==================== 第二步：处理UPDATE和DELETE操作（获取旧对象） ====================
            
            Object oldObject = null;
            String[] includeFields = null;
            String objectId = null;
            
            if (auditLogAnnotation.operationType() == AuditLog.OperationType.UPDATE) {
                // 2.1 验证includeFields是否为空
                includeFields = auditLogAnnotation.includeFields();
                if (includeFields == null || includeFields.length == 0) {
                    log.warn(">>> 警告：UPDATE操作需要指定includeFields字段，跳过审计日志记录");
                } else {
                    // 2.2 从Spring容器获取Mapper实例
                    Object mapper = getMapperFromSpring(joinPoint);
                    if (mapper != null) {
                        // 2.3 从方法参数获取objectId
                        Object[] args = joinPoint.getArgs();
                        Object newObject = args[0]; // 假设第一个参数是新对象
                        objectId = extractId(newObject);

                        if (objectId != null) {
                            // 2.4 查询旧对象
                            oldObject = getOldObject(mapper, objectId);
                        } else {
                            log.warn(">>> 警告：无法从方法参数中提取objectId");
                        }
                    } else {
                        log.warn(">>> 警告：未获取到mapper实例");
                    }
                }
            } else if (auditLogAnnotation.operationType() == AuditLog.OperationType.DELETE) {
                // 2.1 验证includeFields是否为空
                includeFields = auditLogAnnotation.includeFields();
                if (includeFields == null || includeFields.length == 0) {
                    log.warn(">>> 警告：DELETE操作需要指定includeFields字段，跳过审计日志记录");
                } else {
                    // 2.2 从Spring容器获取Mapper实例
                    Object mapper = getMapperFromSpring(joinPoint);
                    if (mapper != null) {
                        // 2.3 从方法参数获取objectId
                        Object[] args = joinPoint.getArgs();
                        objectId = extractId(args[0]);

                        if (objectId != null) {
                            // 2.4 查询要删除的对象
                            oldObject = getOldObject(mapper, objectId);
                        } else {
                            log.warn(">>> 警告：无法从方法参数中提取objectId");
                        }
                    } else {
                        log.warn(">>> 警告：未获取到mapper实例");
                    }
                }
            }
            
            // ==================== 第三步：执行业务方法 ====================
            
            // 真正记录方法开始时间
            startTime = System.currentTimeMillis();
            
            // 执行原方法（始终执行原方法，不受自定义日志保存影响）
            Object result = joinPoint.proceed();
            
            // 计算业务方法耗时
            long duration = System.currentTimeMillis() - startTime;
            
            // ==================== 第四步：处理CREATE操作日志保存 ====================
            
            if (auditLogAnnotation.operationType() == AuditLog.OperationType.CREATE) {
                // 4. 验证includeFields是否为空
                String[] createIncludeFields = auditLogAnnotation.includeFields();
                if (createIncludeFields == null || createIncludeFields.length == 0) {
                    log.warn(">>> 警告：CREATE操作需要指定includeFields字段，跳过审计日志记录");
                } else {
                    // 5. 从ThreadLocalUtil获取objectId
                    String createObjectId = ThreadLocalUtil.getId();
                    
                    if (createObjectId != null) {
                        // 6. 构建审计日志内容
                        String fieldValue = getFieldValue(joinPoint.getArgs()[0], createIncludeFields[0]);
                        String content = "新增" + title + "【" + fieldValue + "】";

                        // 7. 保存审计日志（使用策略模式）
                        String objectType = ThreadLocalUtil.getObjectType();
                        try {
                            if (useCustomLogSave) {
                                executeCustomLogSave(customLogSaveMethod, createObjectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, joinPoint.getArgs(), result, auditStatus, errorMessage, duration, title);
                            } else {
                                // 使用策略模式保存审计日志
                                AuditLogStorageStrategy strategy = strategyFactory.getStrategy(auditLogAnnotation.storeType());
                                strategy.saveAuditLog(createObjectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, auditStatus, errorMessage, duration, title);
                            }
                        } catch (Exception e) {
                            // 日志保存失败，设置状态为失败
                            auditStatus = 0;
                            errorMessage = formatErrorMessage("CREATE日志保存失败", e);
                            log.error(">>> CREATE审计日志保存失败: {}", e.getMessage(), e);
                        }

                        log.info(">>> [线程:{}] CREATE审计日志已提交异步保存", Thread.currentThread().getName());
                    } else {
                        log.warn(">>> 警告：未获取到objectId，跳过审计日志记录");
                    }
                }
            }
            
            // ==================== 第五步：处理UPDATE操作日志保存 ====================
            
            if (auditLogAnnotation.operationType() == AuditLog.OperationType.UPDATE && oldObject != null) {
                String[] updateIncludeFields = auditLogAnnotation.includeFields();
                try {
                    // 9. 获取方法参数（新对象）
                    Object[] args = joinPoint.getArgs();
                    Object newObject = args[0]; // 假设第一个参数是新对象

                    // 10. 比对新旧对象，生成变更内容
                    String changeContent = compareObjects(oldObject, newObject, updateIncludeFields);

                    if (changeContent != null && !changeContent.isEmpty()) {
                        // 11. 从方法参数获取objectId
                        String updateObjectId = extractId(newObject);
                        
                               if (updateObjectId != null) {
                                   // 12. 构建审计日志内容
                                   String content = title + " 从 【" + getOldValuesString(oldObject, updateIncludeFields) + "】 编辑为 【" + getNewValuesString(newObject, updateIncludeFields) + "】";

                                   // 13. 保存审计日志（使用策略模式）
                                   String objectType = ThreadLocalUtil.getObjectType();
                                   try {
                                       if (useCustomLogSave) {
                                           executeCustomLogSave(customLogSaveMethod, updateObjectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, joinPoint.getArgs(), result, auditStatus, errorMessage, duration, title);
                                       } else {
                                           // 使用策略模式保存审计日志
                                           AuditLogStorageStrategy strategy = strategyFactory.getStrategy(auditLogAnnotation.storeType());
                                           strategy.saveAuditLog(updateObjectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, auditStatus, errorMessage, duration, title);
                                       }
                                   } catch (Exception e) {
                                       // 日志保存失败，设置状态为失败
                                       auditStatus = 0;
                                       errorMessage = formatErrorMessage("UPDATE日志保存失败", e);
                                       log.error(">>> UPDATE审计日志保存失败: {}", e.getMessage(), e);
                                   }

                                   log.info(">>> [线程:{}] UPDATE审计日志已提交异步保存", Thread.currentThread().getName());
                               } else {
                                   log.warn(">>> 警告：无法从方法参数中提取objectId");
                               }
                    } else {
                        log.warn(">>> 警告：没有检测到字段变更，跳过审计日志记录");
                    }
                } catch (Exception e) {
                    log.error(">>> 处理UPDATE操作审计日志失败: {}", e.getMessage(), e);
                }
            }
            
            // ==================== 第六步：处理DELETE操作日志保存 ====================
            
            if (auditLogAnnotation.operationType() == AuditLog.OperationType.DELETE && oldObject != null && includeFields != null && includeFields.length > 0) {
                // 使用预先获取的对象信息构建日志
                String fieldValue = getFieldValue(oldObject, includeFields[0]);
                String content = "删除" + title + "【" + fieldValue + "】";
                
                // 保存审计日志（使用策略模式）
                String objectType = ThreadLocalUtil.getObjectType();
                try {
                    if (useCustomLogSave) {
                        executeCustomLogSave(customLogSaveMethod, objectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, joinPoint.getArgs(), result, auditStatus, errorMessage, duration, title);
                    } else {
                        // 使用策略模式保存审计日志
                        AuditLogStorageStrategy strategy = strategyFactory.getStrategy(auditLogAnnotation.storeType());
                        strategy.saveAuditLog(objectId, objectType, content, auditLogAnnotation.operationType().name(), storageTable, auditStatus, errorMessage, duration, title);
                    }
                } catch (Exception e) {
                    // 日志保存失败，设置状态为失败
                    auditStatus = 0;
                    errorMessage = formatErrorMessage("DELETE日志保存失败", e);
                    log.error(">>> DELETE审计日志保存失败: {}", e.getMessage(), e);
                }
                
                log.info(">>> [线程:{}] DELETE审计日志已提交异步保存", Thread.currentThread().getName());
            } else if (auditLogAnnotation.operationType() == AuditLog.OperationType.DELETE) {
                log.warn(">>> 警告：DELETE操作未获取到对象信息，跳过审计日志记录");
            }
            
            return result;
            
        } catch (Exception e) {
            // ==================== 异常处理 ====================
            // 业务方法执行失败，设置状态为失败
            auditStatus = 0;
            errorMessage = formatErrorMessage("业务方法执行失败", e);
            
            // 计算耗时（即使业务失败也要记录耗时）
            long duration = System.currentTimeMillis() - startTime;
            
            log.error(">>> 审计日志记录失败: {}", e.getMessage(), e);
            throw e;
        } finally {
            // ==================== 清理资源 ====================
            // 清理ThreadLocal，防止内存泄漏
            ThreadLocalUtil.clear();
        }
    }
    
    // ==================== 辅助方法 ====================
    
    /**
     * 格式化错误信息，避免过长
     * 
     * @param prefix 错误前缀
     * @param exception 异常对象
     * @return 格式化后的错误信息
     */
    private String formatErrorMessage(String prefix, Exception exception) {
        if (exception == null) {
            return prefix;
        }
        
        String message = exception.getMessage();
        if (message == null || message.trim().isEmpty()) {
            return prefix + ": " + exception.getClass().getSimpleName();
        }
        
        // 限制错误信息长度，避免过长
        int maxLength = 200; // 最大200字符
        if (message.length() > maxLength) {
            message = message.substring(0, maxLength) + "...";
        }
        
        // 清理换行符和多余空格
        message = message.replaceAll("\\s+", " ").trim();
        
        return prefix + ": " + message;
    }
    
    /**
     * 从参数对象中提取ID
     *
     * 支持的对象类型：
     * 1. 有getId()方法的实体对象
     * 2. 基本类型ID（Long、Integer、String等）
     * 3. Map类型的参数（递归查找）
     *
     * @param parameter 方法参数对象
     * @return 提取到的ID，如果提取失败返回null
     */
    private String extractId(Object parameter) {
        if (parameter == null) {
            return null;
        }
        
        // 情况1：参数是基本类型ID（Long、Integer、String等）
        if (parameter instanceof Long || parameter instanceof Integer || 
            parameter instanceof String || parameter instanceof Number) {
            return parameter.toString();
        }
        
        // 情况2：参数是实体对象，尝试调用getId()方法
        try {
            Method getId = parameter.getClass().getMethod("getId");
            Object idValue = getId.invoke(parameter);
            return idValue != null ? idValue.toString() : null;
        } catch (Exception e) {
            // 情况3：参数是Map类型，递归查找
            if (parameter instanceof Map) {
                Map<?, ?> paramMap = (Map<?, ?>) parameter;
                for (Object value : paramMap.values()) {
                    String id = extractId(value);
                    if (id != null) return id;
                }
            }
        }
        return null;
    }
    
    /**
     * 从Spring容器获取Mapper实例
     * 
     * 实现原理：
     * 1. 从Service类名推断对应的Mapper类名
     * 2. 通过反射获取Mapper类
     * 3. 从Spring容器中获取Mapper实例
     * 
     * 命名规则：UserServiceImpl -> UserMapper
     * 
     * @param joinPoint 连接点，用于获取目标类信息
     * @return Mapper实例，如果获取失败返回null
     */
    private Object getMapperFromSpring(ProceedingJoinPoint joinPoint) {
        try {
            // 从方法签名推断mapper类型
            Class<?> targetClass = joinPoint.getTarget().getClass();
            
            // 假设Service实现了XXXService，对应XXXMapper
            String serviceName = targetClass.getSimpleName();
            String entityName = serviceName.replace("ServiceImpl", "").replace("Service", "");
            String mapperClassName = targetClass.getPackage().getName().replace("service", "mapper") + "." + entityName + "Mapper";
            
            Class<?> mapperClass = Class.forName(mapperClassName);
            return applicationContext.getBean(mapperClass);
        } catch (Exception e) {
            log.error(">>> 获取Mapper实例失败: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 查询旧对象
     *
     * 用于UPDATE操作时获取更新前的对象，以便进行字段对比
     *
     * 支持的方法名：
     * 1. selectById(Object.class)
     * 2. selectOne(Object.class)
     * 3. selectById(Serializable.class)
     *
     * @param mapper Mapper实例
     * @param objectId 对象ID
     * @return 旧对象，如果查询失败返回null
     */
    private Object getOldObject(Object mapper, String objectId) {
        try {
            // 尝试不同的方法名
            Method selectByIdMethod = null;
            try {
                // 尝试 selectById 方法
                selectByIdMethod = mapper.getClass().getMethod("selectById", Object.class);
            } catch (NoSuchMethodException e1) {
                try {
                    // 尝试 selectOne 方法
                    selectByIdMethod = mapper.getClass().getMethod("selectOne", Object.class);
                } catch (NoSuchMethodException e2) {
                    // 尝试 selectById 方法，参数为 Serializable
                    selectByIdMethod = mapper.getClass().getMethod("selectById", java.io.Serializable.class);
                }
            }
            
            if (selectByIdMethod != null) {
                return selectByIdMethod.invoke(mapper, objectId);
            } else {
                log.error(">>> 未找到合适的查询方法");
                return null;
            }
        } catch (Exception e) {
            log.error(">>> 查询旧对象失败: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 比对新旧对象，生成变更内容
     * 
     * 功能说明：
     * 1. 遍历指定的字段列表
     * 2. 比较每个字段的旧值和新值
     * 3. 生成格式化的变更描述
     * 
     * 输出格式：fieldName: [oldValue] -> [newValue]
     * 
     * @param oldObject 旧对象
     * @param newObject 新对象
     * @param includeFields 需要比较的字段名数组
     * @return 变更内容字符串，如果没有变更返回null
     */
    private String compareObjects(Object oldObject, Object newObject, String[] includeFields) {
        try {
            if (includeFields == null || includeFields.length == 0) {
                return null;
            }
            
            StringBuilder changeContent = new StringBuilder();
            
            // 遍历需要审计的字段
            for (String fieldName : includeFields) {
                try {
                    Field field = oldObject.getClass().getDeclaredField(fieldName);
                    field.setAccessible(true);
                    
                    Object oldValue = field.get(oldObject);
                    Object newValue = field.get(newObject);
                    
                    // 比较字段值
                    if (!isEqual(oldValue, newValue)) {
                        if (changeContent.length() > 0) {
                            changeContent.append(", ");
                        }
                        changeContent.append(fieldName).append(": ").append(formatValue(oldValue))
                                   .append(" -> ").append(formatValue(newValue));
                    }
                } catch (Exception e) {
                    log.error(">>> 比较字段失败: {}, {}", fieldName, e.getMessage());
                }
            }
            
            return changeContent.toString();
            
        } catch (Exception e) {
            log.error(">>> 比较对象失败: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 比较两个值是否相等
     * 
     * 处理null值的安全比较
     * 
     * @param oldValue 旧值
     * @param newValue 新值
     * @return 如果相等返回true，否则返回false
     */
    private boolean isEqual(Object oldValue, Object newValue) {
        if (oldValue == null && newValue == null) {
            return true;
        }
        if (oldValue == null || newValue == null) {
            return false;
        }
        return oldValue.equals(newValue);
    }
    
    /**
     * 格式化字段值用于显示
     * 
     * 将对象值转换为字符串，处理null值
     * 
     * @param value 要格式化的值
     * @return 格式化后的字符串
     */
    private String formatValue(Object value) {
        if (value == null) {
            return "null";
        }
        return value.toString();
    }
    
    /**
     * 获取指定字段的值
     * 从对象中提取指定字段的值，用于CREATE/DELETE操作的日志显示
     * 
     * @param obj 目标对象
     * @param fieldName 字段名
     * @return 字段值，如果提取失败返回"未知"
     */
    private String getFieldValue(Object obj, String fieldName) {
        try {
            if (obj != null && fieldName != null && !fieldName.trim().isEmpty()) {
                Field field = obj.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object value = field.get(obj);
                return formatValue(value);
            }
        } catch (Exception e) {
            log.warn(">>> 获取字段值失败: {}, 错误: {}", fieldName, e.getMessage());
        }
        return "未知";
    }
    
    
    /**
     * 获取旧对象的值字符串
     * 用于UPDATE操作中显示旧值
     * 
     * @param oldObject 旧对象
     * @param includeFields 需要显示的字段
     * @return 旧值字符串，格式：字段1值,字段2值
     */
    private String getOldValuesString(Object oldObject, String[] includeFields) {
        if (oldObject == null || includeFields == null || includeFields.length == 0) {
            return "";
        }
        
        StringBuilder values = new StringBuilder();
        for (int i = 0; i < includeFields.length; i++) {
            try {
                Field field = oldObject.getClass().getDeclaredField(includeFields[i]);
                field.setAccessible(true);
                Object value = field.get(oldObject);
                if (i > 0) {
                    values.append(",");
                }
                values.append(formatValue(value));
            } catch (Exception e) {
                log.warn(">>> 获取旧值失败: {}", includeFields[i]);
                if (i > 0) {
                    values.append(",");
                }
                values.append("null");
            }
        }
        return values.toString();
    }
    
    /**
     * 获取新对象的值字符串
     * 用于UPDATE操作中显示新值
     * 
     * @param newObject 新对象
     * @param includeFields 需要显示的字段
     * @return 新值字符串，格式：字段1值,字段2值
     */
    private String getNewValuesString(Object newObject, String[] includeFields) {
        if (newObject == null || includeFields == null || includeFields.length == 0) {
            return "";
        }
        
        StringBuilder values = new StringBuilder();
        for (int i = 0; i < includeFields.length; i++) {
            try {
                Field field = newObject.getClass().getDeclaredField(includeFields[i]);
                field.setAccessible(true);
                Object value = field.get(newObject);
                if (i > 0) {
                    values.append(",");
                }
                values.append(formatValue(value));
            } catch (Exception e) {
                log.warn(">>> 获取新值失败: {}", includeFields[i]);
                if (i > 0) {
                    values.append(",");
                }
                values.append("null");
            }
        }
        return values.toString();
    }
    
    // ==================== 自定义日志保存方法 ====================
    
    /**
     * 执行自定义日志保存方法
     *
     * 功能说明：
     * 1. 解析全路径方法名（类名.方法名）
     * 2. 从Spring容器获取目标Bean
     * 3. 通过反射调用自定义日志保存方法
     * 4. 异常处理：记录错误日志，不降级
     *
     * 方法签名要求：
     * public void methodName(String objectId, String objectType, String content, String operationType, String storageTable, Object[] methodArgs, Object returnValue, Integer auditStatus, String errorMessage, Long duration, String title)
     *
     * @param fullPathMethodName 全路径方法名，格式：com.package.ClassName.methodName
     * @param objectId 操作对象ID
     * @param objectType 对象类型（表名）
     * @param content 日志内容
     * @param operationType 操作类型
     * @param storageTable 自定义存储表名
     * @param methodArgs 原方法入参
     * @param returnValue 原方法返回值
     * @param auditStatus 审计状态
     * @param errorMessage 错误信息
     * @param duration 耗时
     * @param title 标题
     */
    private void executeCustomLogSave(String fullPathMethodName, String objectId, String objectType, String content, String operationType, String storageTable, Object[] methodArgs, Object returnValue, Integer auditStatus, String errorMessage, Long duration, String title) {
        try {
            // 解析全路径格式
            int lastDotIndex = fullPathMethodName.lastIndexOf('.');
            if (lastDotIndex == -1 || lastDotIndex == fullPathMethodName.length() - 1) {
                //TODO替换BusinessException
                throw new IllegalArgumentException("无效的全路径格式: " + fullPathMethodName + 
                    ", 正确格式: com.package.ClassName.methodName");
            }
            
            String className = fullPathMethodName.substring(0, lastDotIndex);
            String methodName = fullPathMethodName.substring(lastDotIndex + 1);
            
            log.info(">>> 使用自定义日志保存方法 - 类名: {}, 方法名: {}", className, methodName);
            
            // 从Spring容器获取目标bean
            Class<?> targetClass = Class.forName(className);
            Object targetBean = applicationContext.getBean(targetClass);
            
                   // 查找目标方法，参数必须是 (String objectId, String objectType, String content, String operationType, String storageTable, Object[] methodArgs, Object returnValue, Integer auditStatus, String errorMessage, Long duration, String title)
                   Method targetMethod = targetClass.getMethod(methodName, String.class, String.class, String.class, String.class, String.class, Object[].class, Object.class, Integer.class, String.class, Long.class, String.class);
            
            // 验证返回类型必须是void
            if (!void.class.equals(targetMethod.getReturnType())) {
                //TODO替换BusinessException
                throw new IllegalArgumentException("自定义日志保存方法 " + fullPathMethodName + 
                    " 的返回类型必须是void，当前返回类型: " + targetMethod.getReturnType().getSimpleName());
            }
            
            // 调用自定义日志保存方法
            targetMethod.invoke(targetBean, objectId, objectType, content, operationType, storageTable, methodArgs, returnValue, auditStatus, errorMessage, duration, title);
            
            log.info(">>> 成功执行自定义日志保存方法: {}", fullPathMethodName);
            
        } catch (ClassNotFoundException e) {
            log.error(">>> 未找到自定义日志保存类: {}", e.getMessage(), e);
        } catch (NoSuchMethodException e) {
            log.error(">>> 未找到自定义日志保存方法: {}, 错误: {}", fullPathMethodName, e.getMessage());
        } catch (Exception e) {
            log.error(">>> 执行自定义日志保存方法失败: {}, 错误: {}", fullPathMethodName, e.getMessage(), e);
        }
    }
}
